﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Reflection;
using Go;

namespace GoRpc
{
    static public class Rpc
    {
        enum DataType
        {
            Keep,
            NoKeep,
            Close,
            Request,
            RequestCancel,
            Reply,
            Bin,
            BinCancel,
        }

        [Serializable]
        struct Request
        {
            public bool reply;
            public string name;
            public RecvName[] sends;
        }

        [Serializable]
        struct Reply
        {
            public ReplyState state;
            public string message;
        }

        [Serializable]
        public enum ReplyState
        {
            Success,
            Overtime,
            Stopped,
            Exception,
            ArgumentException,
            TargetParameterCountException,
            NotFound,
            LocalCancel,
            RemoteCancel,
            ResultTypeError,
            LocalSerializeError,
            RemoteSerializeError,
            LocalDeserializeError,
            RemoteDeserializeError,
            Fail,
        }

        public class Methods
        {
            struct BindObjInfo
            {
                public bool isTask;
                public MethodInfo method;
                public MethodInfo valueTask;
                public MethodInfo getResult;
            }

            static long _nameid = DateTime.Now.Ticks;
            Dictionary<string, Func<async_result_wrap<object, ReplyState>, object[], Task>> _methodsMap =
                new Dictionary<string, Func<async_result_wrap<object, ReplyState>, object[], Task>>();

            static public string GenName
            {
                get
                {
                    return $"GoRpcMethod_{Interlocked.Increment(ref _nameid)}";
                }
            }

            public void Bind(string name, Func<object[], Task> handler)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => handler(args));
            }

            public void Bind(string name, Func<object[], ValueTask> handler)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => handler(args).AsTask() ?? generator.non_async());
            }

            public void Bind(string name, Func<object[], ValueTask<void_type>> handler)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => handler(args).AsTask() ?? generator.non_async());
            }

            private async Task bind_wait<R>(async_result_wrap<object, ReplyState> resWrap, Task<R> task)
            {
                resWrap.value1 = await task;
            }

            public void Bind<R>(string name, Func<object[], Task<R>> handler)
            {
                Add(name, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    Task<R> task = handler(args);
                    if (!task.IsCompleted)
                    {
                        return bind_wait(resWrap, task);
                    }
                    resWrap.value1 = task.GetAwaiter().GetResult();
                    return generator.non_async();
                });
            }

            public void Bind<R>(string name, Func<object[], ValueTask<R>> handler)
            {
                Add(name, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    ValueTask<R> task = handler(args);
                    if (!task.IsCompleted)
                    {
                        return bind_wait(resWrap, task.AsTask());
                    }
                    resWrap.value1 = task.GetAwaiter().GetResult();
                    return generator.non_async();
                });
            }

            public void Bind(string name, Action<object[]> handler)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => { handler(args); return generator.non_async(); });
            }

            public void Bind<R>(string name, Func<object[], R> handler)
            {
                Debug.Assert("Task`1" != typeof(R).Name && "Task" != typeof(R).Name && "ValueTask`1" != typeof(R).Name, "Bind 不能绑定异步操作");
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => { resWrap.value1 = handler(args); return generator.non_async(); });
            }

            public string[] BindObj<T>(string name, T obj)
            {
                Type type = typeof(T);
                MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
                Dictionary<string, LinkedList<BindObjInfo>> overrideMethod = new Dictionary<string, LinkedList<BindObjInfo>>();
                LinkedList<string> allBinds = new LinkedList<string>();
                for (int i = 0; i < methods.Length; i++)
                {
                    BindObjInfo methodInfo = new BindObjInfo { method = methods[i] };
                    Type returnType = methodInfo.method.ReturnType;
                    if ((methodInfo.isTask = ("Task`1" == returnType.Name || "Task" == returnType.Name)) &&
                        "System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult]" != returnType.ToString())
                    {
                        methodInfo.getResult = returnType.GetMethod("get_Result", BindingFlags.Instance | BindingFlags.Public);
                    }
                    else if ("ValueTask`1" == returnType.Name)
                    {
                        methodInfo.valueTask = returnType.GetMethod("AsTask", BindingFlags.Instance | BindingFlags.Public);
                        methodInfo.getResult = returnType.GetMethod("get_Result", BindingFlags.Instance | BindingFlags.Public);
                    }
                    LinkedList<BindObjInfo> dupName;
                    string methodName = methodInfo.method.Name;
                    if (!overrideMethod.TryGetValue(methodName, out dupName))
                    {
                        dupName = new LinkedList<BindObjInfo>();
                        overrideMethod.Add(methodName, dupName);
                        string key = $"{name}.{methodName}";
                        allBinds.AddLast(key);
                        Add(key, async delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                        {
                            BindObjInfo invokeMethod = default;
                            if (1 == dupName.Count)
                            {
                                invokeMethod = dupName.First.Value;
                            }
                            else
                            {
                                foreach (BindObjInfo item in dupName)
                                {
                                    ParameterInfo[] parameters = item.method.GetParameters();
                                    if (parameters.Length == args.Length)
                                    {
                                        bool eq = true;
                                        for (int j = 0; j < args.Length && eq; j++)
                                        {
                                            eq = parameters[j].ParameterType == args[j].GetType();
                                        }
                                        if (eq)
                                        {
                                            invokeMethod = item;
                                            break;
                                        }
                                    }
                                }
                            }
                            if (null != invokeMethod.method)
                            {
                                if (invokeMethod.isTask)
                                {
                                    Task result;
                                    await (result = (Task)invokeMethod.method.Invoke(obj, args));
                                    resWrap.value1 = null == invokeMethod.getResult ? null : invokeMethod.getResult.Invoke(result, null);
                                }
                                else if (null != invokeMethod.valueTask)
                                {
                                    object result = invokeMethod.method.Invoke(obj, args);
                                    Task task = (Task)invokeMethod.valueTask.Invoke(result, null);
                                    if (null != task) await task;
                                    resWrap.value1 = invokeMethod.getResult.Invoke(result, null);
                                }
                                else if (null == Session.OverRecv())
                                {
                                    resWrap.value1 = await generator.send_task(() => invokeMethod.method.Invoke(obj, args));
                                }
                                else
                                {
                                    resWrap.value1 = invokeMethod.method.Invoke(obj, args);
                                }
                            }
                            else
                            {
                                resWrap.value2 = ReplyState.ArgumentException;
                            }
                        });
                    }
                    dupName.AddLast(methodInfo);
                }

                FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
                for (int i = 0; i < fields.Length; i++)
                {
                    try
                    {
                        FieldInfo field = fields[i];
                        string key1 = $"{name}.get@{field.Name}";
                        string key2 = $"{name}.set@{field.Name}";
                        allBinds.AddLast(key1);
                        allBinds.AddLast(key2);
                        Add(key1, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                        {
                            resWrap.value1 = field.GetValue(obj);
                            return generator.non_async();
                        });
                        Add(key2, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                        {
                            field.SetValue(obj, args[0]);
                            return generator.non_async();
                        });
                    }
                    catch (System.ArgumentException) { }
                }
                return allBinds.ToArray();
            }

            private void Add(string name, Func<async_result_wrap<object, ReplyState>, object[], Task> handler)
            {
                lock (_methodsMap) _methodsMap.Add(name, handler);
            }

            internal bool Get(string name, out Func<async_result_wrap<object, ReplyState>, object[], Task> handler)
            {
                lock (_methodsMap) return _methodsMap.TryGetValue(name, out handler);
            }

            public bool Remove(string name)
            {
                lock (_methodsMap) return _methodsMap.Remove(name);
            }

            public void Remove(params string[] names)
            {
                foreach (var name in names)
                {
                    Remove(name);
                }
            }

            public void Clear()
            {
                lock (_methodsMap) _methodsMap.Clear();
            }
        }

        public class RpcException : Exception
        {
            public ReplyState code;

            public RpcException(ReplyState st)
            {
                code = st;
            }
        }

        public struct Result
        {
            public ReplyState state;
            public string message;
            public object result;

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }
        }

        public struct Result<R>
        {
            public ReplyState state;
            public string message;
            public R result;

            public static implicit operator R(Result<R> rval)
            {
                rval.Check();
                return rval.result;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }
        }

        public class OverSend
        {
            bool closed;
            wait_group wg;
            internal LinkedList<tuple<Func<bool, ValueTask>, RecvName>> actions;

            internal OverSend()
            {
                closed = false;
                wg = new wait_group(1);
                actions = new LinkedList<tuple<Func<bool, ValueTask>, RecvName>>();
            }

            public bool Closed
            {
                get
                {
                    return closed;
                }
            }

            public void AppendNotify(Action notify)
            {
                wg.async_wait(notify);
            }

            public Task Wait()
            {
                return generator.wait_group(wg);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_group(ms, wg);
            }

            internal RecvName[] Sends()
            {
                if (0 == actions.Count)
                {
                    return null;
                }
                RecvName[] sends = new RecvName[actions.Count];
                int i = 0;
                foreach (var item in actions)
                {
                    sends[i++] = item.value2;
                }
                return sends;
            }

            internal void Notify()
            {
                wg.done();
            }

            internal void Close()
            {
                closed = true;
                wg.done();
            }
        }

        public struct RpcCancel
        {
            internal wait_group wg;

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void AppendNotify(Action notify)
            {
                wg.async_wait(notify);
            }

            public Task Wait()
            {
                return generator.wait_group(wg);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_group(ms, wg);
            }
        }

        public struct OverCancel
        {
            internal wait_group wg;

            static public OverCancel Make()
            {
                return new OverCancel
                {
                    wg = new wait_group(1)
                };
            }

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void Cancel()
            {
                wg.force();
            }
        }

        public class CancelException : Exception
        {
            static readonly internal CancelException Instance = new CancelException();
            private CancelException() { }
        }

        [Serializable]
        internal struct RecvName
        {
            public SendName name;
            public long count;
            public int segment;
        }

        public class OverRecv
        {
            internal OverRecv() { }
            internal bool _cancel;
            internal long _offset;
            internal RecvName recvName;

            public bool Cancel => _cancel;
            public bool Big => Length > int.MaxValue;
            public bool Full => _offset == recvName.count;
            public long Offset => _offset;
            public long Length => recvName.count;
            public int Segment => recvName.segment;
            public SendName Name => recvName.name;
        }

        class OverSendState
        {
            public class ResultException : Exception
            {
                static readonly internal ResultException Instance = new ResultException();
                private ResultException() { }
            }

            public class NamedException : Exception
            {
                static readonly internal NamedException Instance = new NamedException();
                private NamedException() { }
            }

            public class CountException : Exception
            {
                static readonly internal CountException Instance = new CountException();
                private CountException() { }
            }

            public SendName name;
            public long maxCount;
            public long count;
            public ValueTask<csp_invoke_wrap<void_type>> task;

            public void SetTask(ValueTask<csp_invoke_wrap<void_type>> task)
            {
                this.task = task;
            }
        }

        [Serializable]
        public struct SendName : IComparable
        {
            static long _inc = 0;
            internal long id;

            public SendName(long id)
            {
                Debug.Assert(id > 0, "数据命名ID要大于0");
                this.id = id;
            }

            static public SendName Make()
            {
                return new SendName { id = Interlocked.Increment(ref _inc) };
            }

            public int CompareTo(object value)
            {
                return id.CompareTo(((SendName)value).id);
            }

            public bool Nil
            {
                get
                {
                    return id <= 0;
                }
            }

            public override string ToString()
            {
                return id.ToString();
            }
        }

        public class RecvDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            bool error;

            public RecvDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public RecvDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                error = false;
            }

            public void Async(Action handler)
            {
                Debug.Assert(task.is_done, "RecvDoubleBuffer 异步任务未结束");
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] WriteData
            {
                get
                {
                    return buff1;
                }
            }

            public byte[] RecvBuff
            {
                get
                {
                    return buff2;
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class SendDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            int count;
            bool error;

            public SendDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public SendDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                count = 0;
                error = false;
            }

            public void Async(Func<int> handler)
            {
                Debug.Assert(task.is_done, "SendDoubleBuffer 异步任务未结束");
                count = 0;
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        count = handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] ReadBuff
            {
                get
                {
                    return buff1;
                }
            }

            public ArraySegment<byte> SendData
            {
                get
                {
                    return new ArraySegment<byte>(buff2, 0, count);
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class Session
        {
            public enum ExitCode
            {
                Undefined,
                LocalClose,
                RemoteClose,
                SessionClose,
                SocketClosed,
                KeepOvertime,
                RecvOvertime,
                ReadOvertime,
                WriteOvertime,
                DataHeadError,
                ReplySerializeError,
                RequestSerializeError,
                ReplyDeserializeError,
                RequestDeserializeError,
            }

            struct SendByteParam
            {
                public long id;
                public int timed;
                public ArraySegment<byte> data;
            }

            struct SendPtrParam
            {
                public long id;
                public int timed;
                public IntPtr pointer;
                public long offset;
                public int count;
                public object pinnedObj;
            }

            struct SendFileParam
            {
                public long id;
                public int timed;
                public SafeHandle file;
                public long offset;
                public int count;
                public object pinnedObj;
            }

            struct RpcParam
            {
                public long id;
                public int timed;
                public object[] args;
                public Request request;
                public OverSend overSend;
                public OverCancel overCancel;
            }

            struct RecvPtrParam
            {
                public int timed;
                public IntPtr pointer;
                public long offset;
                public int count;
                public object pinnedObj;
            }

            struct RecvByteParam
            {
                public int timed;
                public ArraySegment<byte> buff;
            }

            struct NamedRecvParam
            {
                public long id;
                public NamedCsp csp;
            }

            struct RecvList
            {
                public OverRecv[] recvs;
            }

            struct OverCallbackList
            {
                public LinkedList<string> names;
            }

            enum NamedType
            {
                Byte,
                Ptr
            }

            interface NamedCsp
            {
                NamedType Type { get; }
                void Close();
            }

            class NamedByteCsp : csp_chan<int, RecvByteParam>, NamedCsp
            {
                public NamedByteCsp(shared_strand strand) : base(strand) { }
                public NamedType Type => NamedType.Byte;
                public void Close() => base.close();
            }

            class NamedPtrCsp : csp_chan<int, RecvPtrParam>, NamedCsp
            {
                public NamedPtrCsp(shared_strand strand) : base(strand) { }
                public NamedType Type => NamedType.Ptr;
                public void Close() => base.close();
            }

            static generator.local<Session> _session = new generator.local<Session>();
            static byte[] _lostBinBuff = new byte[1024 * 1024];
            static long _idCount = DateTime.Now.Ticks;
            static int _keep = 10000;

            int _exitCode;
            socket _socket;
            Methods _methods;
            generator _action;
            shared_strand[] _strands;
            generator.local<OverSend> _overSend;
            generator.local<RecvList> _recvList;
            generator.local<RpcCancel> _rpcCancel;
            generator.local<OverCancel> _overCancel;
            generator.local<OverSendState> _overSendState;
            generator.local<OverCallbackList> _overCallbackList;
            csp_chan<Result, RpcParam> _rpcChan;
            csp_chan<void_type, long> _cancelSendChan;
            csp_chan<void_type, SendByteParam> _sendByteChan;
            csp_chan<void_type, SendPtrParam> _sendPtrChan;
            csp_chan<void_type, SendFileParam> _sendFileChan;
            csp_chan<int, RecvPtrParam> _recvPtrChan;
            csp_chan<int, RecvByteParam> _recvByteChan;
            chan<NamedRecvParam> _namedRecvChan;
            chan<DataType> _remoteCmdChan;
            chan<long> _cancelRpcChan;

            public Session(shared_strand[] strands, socket socket, Methods methods)
            {
                _socket = socket;
                _methods = methods;
                _strands = strands;
                _exitCode = (int)ExitCode.Undefined;
                _overSend = new generator.local<OverSend>();
                _recvList = new generator.local<RecvList>();
                _rpcCancel = new generator.local<RpcCancel>();
                _overCancel = new generator.local<OverCancel>();
                _overSendState = new generator.local<OverSendState>();
                _overCallbackList = new generator.local<OverCallbackList>();
                _rpcChan = new csp_chan<Result, RpcParam>(_strands[0]);
                _cancelSendChan = new csp_chan<void_type, long>(_strands[0]);
                _sendByteChan = new csp_chan<void_type, SendByteParam>(_strands[0]);
                _sendPtrChan = new csp_chan<void_type, SendPtrParam>(_strands[0]);
                _sendFileChan = new csp_chan<void_type, SendFileParam>(_strands[0]);
                _recvPtrChan = new csp_chan<int, RecvPtrParam>(_strands[0]);
                _recvByteChan = new csp_chan<int, RecvByteParam>(_strands[0]);
                _namedRecvChan = chan<NamedRecvParam>.make(_strands[0], -1);
                _remoteCmdChan = chan<DataType>.make(_strands[0], -1);
                _cancelRpcChan = chan<long>.make(_strands[0], -1);
                _action = generator.make(_strands[0], () => Run(), delegate ()
                {
                    _rpcChan.close();
                    _cancelSendChan.close();
                    _sendByteChan.close();
                    _sendPtrChan.close();
                    _sendFileChan.close();
                    _recvPtrChan.close();
                    _recvByteChan.close();
                    _namedRecvChan.close();
                    _remoteCmdChan.close();
                    _cancelRpcChan.close();
                });
            }

            public Session(shared_strand strand, socket socket, Methods methods)
                : this(new shared_strand[] { strand }, socket, methods) { }

            public void Start()
            {
                _action.run();
            }

            public void Close()
            {
                _action.stop();
            }

            public void AppendNotify(Action notify)
            {
                _action.append_stop_callback(notify);
            }

            public Task Wait()
            {
                return generator.wait_other(_action);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_other(ms, _action);
            }

            public bool Closed
            {
                get
                {
                    return _action.is_completed();
                }
            }

            public ExitCode Code
            {
                get
                {
                    return (ExitCode)_exitCode;
                }
            }

            public Methods Methods
            {
                get
                {
                    return _methods;
                }
            }

            static private void Swap<T>(ref T a, ref T b)
            {
                T t = a;
                a = b;
                b = t;
            }

            static private int Read32(byte[] buff, int offset)
            {
                return (buff[offset + 0] << (0 * 8))
                 | (buff[offset + 1] << (1 * 8))
                 | (buff[offset + 2] << (2 * 8))
                 | (buff[offset + 3] << (3 * 8));
            }

            static private long Read64(byte[] buff, int offset)
            {
                return ((long)buff[offset + 0] << (0 * 8))
                 | ((long)buff[offset + 1] << (1 * 8))
                 | ((long)buff[offset + 2] << (2 * 8))
                 | ((long)buff[offset + 3] << (3 * 8))
                 | ((long)buff[offset + 4] << (4 * 8))
                 | ((long)buff[offset + 5] << (5 * 8))
                 | ((long)buff[offset + 6] << (6 * 8))
                 | ((long)buff[offset + 7] << (7 * 8));
            }

            static private void Write32(int val, byte[] buff, int offset)
            {
                buff[offset + 0] = (byte)(val >> (0 * 8));
                buff[offset + 1] = (byte)(val >> (1 * 8));
                buff[offset + 2] = (byte)(val >> (2 * 8));
                buff[offset + 3] = (byte)(val >> (3 * 8));
            }

            static private void Write64(long val, byte[] buff, int offset)
            {
                buff[offset + 0] = (byte)(val >> (0 * 8));
                buff[offset + 1] = (byte)(val >> (1 * 8));
                buff[offset + 2] = (byte)(val >> (2 * 8));
                buff[offset + 3] = (byte)(val >> (3 * 8));
                buff[offset + 4] = (byte)(val >> (4 * 8));
                buff[offset + 5] = (byte)(val >> (5 * 8));
                buff[offset + 6] = (byte)(val >> (6 * 8));
                buff[offset + 7] = (byte)(val >> (7 * 8));
            }

            static private void ReadHead(byte[] recvHead, out long id, out int len1, out int len2, out DataType type)
            {
                id = Read64(recvHead, 0);
                len1 = Read32(recvHead, 8);
                len2 = Read32(recvHead, 12);
                type = (DataType)recvHead[16];
            }

            static private void WriteHead(byte[] sendHead, long id, int len1, int len2, DataType type)
            {
                Write64(id, sendHead, 0);
                Write32(len1, sendHead, 8);
                Write32(len2, sendHead, 12);
                sendHead[16] = (byte)type;
            }

            static public Session Self
            {
                get
                {
                    _session.get(out Session self);
                    return self;
                }
            }

            static public RpcCancel CancelWait()
            {
                Session self = Self;
                Debug.Assert(null != self, "不在 Rpc.Session 上下文中");
                self._rpcCancel.get(out RpcCancel value);
                return value;
            }

            static public OverRecv[] OverRecv()
            {
                Session self = Self;
                Debug.Assert(null != self, "不在 Rpc.Session 上下文中");
                if (!self._recvList.get(out RecvList value))
                {
                    return null;
                }
                return value.recvs;
            }

            static public void ThrowCancel()
            {
                Session self = Self;
                Debug.Assert(null != self, "不在 Rpc.Session 上下文中");
                throw CancelException.Instance;
            }

            static public void DisableKeep()
            {
                _keep = int.MaxValue;
            }

            public async Task DiscardRecv(OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                generator.lock_shield();
                for (int i = 0; i < recvs.Length; i++)
                {
                    while (!recvs[i].Full && !recvs[i].Cancel)
                    {
                        await NamedRecv(recvs[i], _lostBinBuff, 0, _lostBinBuff.Length);
                    }
                }
                await generator.unlock_shield();
            }

            public async Task DiscardChaoticRecv(params OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                generator.lock_shield();
                generator.children children = new generator.children();
                children.ignore_suspend();
                for (int i = 0; i < recvs.Length; i++)
                {
                    int j = i;
                    children.go(async delegate ()
                    {
                        while (!recvs[j].Full && !recvs[j].Cancel)
                        {
                            await NamedRecv(recvs[j], _lostBinBuff, 0, _lostBinBuff.Length);
                        }
                    });
                }
                await children.wait_all();
                await generator.unlock_shield();
            }

            public OverCancel OverCancel()
            {
                Debug.Assert(!_overCancel.get(out _), "重复的 OverCancel");
                OverCancel call = Rpc.OverCancel.Make();
                _overCancel.value = call;
                return call;
            }

            public void OverCancel(OverCancel call)
            {
                Debug.Assert(!_overCancel.get(out _), "重复的 OverCancel");
                _overCancel.value = call;
            }

            public OverSend OverSend()
            {
                Debug.Assert(!_overSend.get(out _), "重复的 OverSend");
                OverSend send = new OverSend();
                _overSend.value = send;
                return send;
            }

            private void OverNamedSend(Func<bool, ValueTask> action, SendName name, long count, int segment)
            {
                if (!_overSend.get(out OverSend send))
                {
                    send = new OverSend();
                    _overSend.value = send;
                }
                send.actions.AddLast(tuple.make(action, new RecvName { name = name, count = count, segment = segment }));
            }

            private void OverNamedSend(Func<bool, Task> action, SendName name, long count, int segment)
            {
                OverNamedSend((bool cancel) => new ValueTask(action(cancel)), name, count, segment);
            }

            private void OverNamedSend(Func<bool, ValueTask<csp_invoke_wrap<void_type>>> action, SendName name, long count, int segment)
            {
                OverNamedSend((bool cancel) => new ValueTask(action(cancel).AsTask()), name, count, segment);
            }

            private OverSendState CheckOverSendState(SendName name, int count)
            {
                if (_overSendState.get(out OverSendState sendState))
                {
                    if (!sendState.task.IsCompleted)
                    {
                        throw OverSendState.ResultException.Instance;
                    }
                    if (sendState.name.id != name.id)
                    {
                        throw OverSendState.NamedException.Instance;
                    }
                    if (count > sendState.maxCount)
                    {
                        throw OverSendState.CountException.Instance;
                    }
                    sendState.count += count;
                    sendState.maxCount -= count;
                }
                return sendState;
            }

            public SendName OverNamedSend(long count, Func<SendName, long, long, ValueTask<csp_invoke_wrap<void_type>>> sendAction)
            {
                SendName name = SendName.Make();
                OverNamedSend(name, count, sendAction);
                return name;
            }

            public SendName OverNamedSend(long count, Func<SendName, long, long, Task> sendAction)
            {
                SendName name = SendName.Make();
                OverNamedSend(name, count, sendAction);
                return name;
            }

            public void OverNamedSend(SendName name, long count, Func<SendName, long, long, ValueTask<csp_invoke_wrap<void_type>>> sendAction)
            {
                OverNamedSend(name, count, (SendName name_, long offset_, long count_) => sendAction(name_, offset_, count_).AsTask() ?? generator.non_async());
            }

            public void OverNamedSend(SendName name, long count, Func<SendName, long, long, Task> sendAction)
            {
                OverNamedSend(async delegate (bool cancel)
                {
                    if (cancel)
                    {
                        await CancelNamedSend(name);
                        return;
                    }
                    try
                    {
                        OverSendState sendState = new OverSendState { name = name };
                        _overSendState.value = sendState;
                        for (long off = 0; off < count;)
                        {
                            if (0 != off)
                            {
                                generator.lock_stop();
                            }
                            sendState.count = 0;
                            sendState.maxCount = count - off;
                            await sendAction(name, off, count - off);
                            if (!sendState.task.IsCompleted)
                            {
                                throw OverSendState.ResultException.Instance;
                            }
                            chan_state state = sendState.task.Result;
                            long len = sendState.count;
                            if (len <= 0)
                            {
                                await CancelNamedSend(name);
                                break;
                            }
                            if (state != chan_state.ok)
                            {
                                break;
                            }
                            off += len;
                            if (count != off)
                            {
                                generator.unlock_stop();
                            }
                        }
                    }
                    catch (OverSendState.ResultException)
                    {
                        await CancelNamedSend(name);
                        Debug.Assert(false, "OverNamedSend 发送异步结果未结束");
                    }
                    catch (OverSendState.NamedException)
                    {
                        await CancelNamedSend(name);
                        Debug.Assert(false, "OverNamedSend 中的 SendName 不匹配");
                    }
                    catch (OverSendState.CountException)
                    {
                        await CancelNamedSend(name);
                        Debug.Assert(false, "OverNamedSend 发送长度溢出");
                    }
                    catch (generator.stop_exception)
                    {
                        await CancelNamedSend(name);
                        throw;
                    }
                    finally
                    {
                        _overSendState.remove();
                    }
                }, name, count, 0);
            }

            public SendName OverNamedSend(ArraySegment<byte> data, int segment = 0)
            {
                return OverNamedTimedSend(-1, data, segment);
            }

            public void OverNamedSend(SendName name, ArraySegment<byte> data, int segment = 0)
            {
                OverNamedTimedSend(name, -1, data, segment);
            }

            public SendName OverNamedSend(byte[] data, int offset, int count, int segment = 0)
            {
                return OverNamedTimedSend(-1, data, offset, count, segment);
            }

            public void OverNamedSend(SendName name, byte[] data, int offset, int count, int segment = 0)
            {
                OverNamedTimedSend(name, -1, data, offset, count, segment);
            }

            public SendName OverNamedSend(IntPtr pointer, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                return OverNamedTimedSend(-1, pointer, offset, count, segment, pinnedObj);
            }

            public void OverNamedSend(SendName name, IntPtr pointer, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                OverNamedTimedSend(name, -1, pointer, offset, count, segment, pinnedObj);
            }

            public SendName OverNamedSend(SafeHandle file, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                return OverNamedTimedSend(-1, file, offset, count, segment, pinnedObj);
            }

            public void OverNamedSend(SendName name, SafeHandle file, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                OverNamedTimedSend(name, -1, file, offset, count, segment, pinnedObj);
            }

            public SendName OverNamedTimedSend(int timed, ArraySegment<byte> data, int segment = 0)
            {
                SendName name = SendName.Make();
                OverNamedTimedSend(name, timed, data, segment);
                return name;
            }

            public void OverNamedTimedSend(SendName name, int timed, ArraySegment<byte> data, int segment = 0)
            {
                if (segment > 0 && segment < data.Count)
                {
                    OverNamedSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelNamedSend(name);
                            return;
                        }
                        try
                        {
                            for (int off = 0; off < data.Count;)
                            {
                                int len = Math.Min(data.Count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                chan_state state = await NamedTimedSend(name, tuple.make(-1, timed), new ArraySegment<byte>(data.Array, data.Offset + off, len));
                                if (state != chan_state.ok)
                                {
                                    break;
                                }
                                off += len;
                                if (data.Count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelNamedSend(name);
                            throw;
                        }
                    }, name, data.Count, segment);
                }
                else
                {
                    OverNamedSend((bool cancel) => cancel ? CancelNamedSend(name) : NamedTimedSend(name, tuple.make(-1, timed), data), name, data.Count, 0);
                }
            }

            public SendName OverNamedTimedSend(int timed, byte[] data, int offset, int count, int segment = 0)
            {
                return OverNamedTimedSend(timed, new ArraySegment<byte>(data, offset, count), segment);
            }

            public void OverNamedTimedSend(SendName name, int timed, byte[] data, int offset, int count, int segment = 0)
            {
                OverNamedTimedSend(name, timed, new ArraySegment<byte>(data, offset, count), segment);
            }

            public SendName OverNamedTimedSend(int timed, IntPtr pointer, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                SendName name = SendName.Make();
                OverNamedTimedSend(name, timed, pointer, offset, count, segment, pinnedObj);
                return name;
            }

            public void OverNamedTimedSend(SendName name, int timed, IntPtr pointer, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    OverNamedSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelNamedSend(name);
                            return;
                        }
                        try
                        {
                            for (long off = 0; off < count;)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                chan_state state = await NamedTimedSend(name, tuple.make(-1, timed), new IntPtr(pointer.ToInt64() + offset + off), 0, len, pinnedObj);
                                if (state != chan_state.ok)
                                {
                                    break;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelNamedSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    OverNamedSend((bool cancel) => cancel ? CancelNamedSend(name) : NamedTimedSend(name, tuple.make(-1, timed), new IntPtr(pointer.ToInt64() + offset), 0, (int)count, pinnedObj), name, count, 0);
                }
            }

            public SendName OverNamedTimedSend(int timed, SafeHandle file, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                SendName name = SendName.Make();
                OverNamedTimedSend(name, timed, file, offset, count, segment, pinnedObj);
                return name;
            }

            public void OverNamedTimedSend(SendName name, int timed, SafeHandle file, long offset, long count, int segment = 0, object pinnedObj = null)
            {
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    OverNamedSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelNamedSend(name);
                            return;
                        }
                        try
                        {
                            for (long off = 0; off < count;)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                chan_state state = await NamedTimedSend(name, tuple.make(-1, timed), file, offset + off, len, pinnedObj);
                                if (state != chan_state.ok)
                                {
                                    break;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelNamedSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    OverNamedSend((bool cancel) => cancel ? CancelNamedSend(name) : NamedTimedSend(name, tuple.make(-1, timed), file, offset, (int)count, pinnedObj), name, count, 0);
                }
            }

            public void CancelOverSend()
            {
                _overSend.remove();
            }

            private void CheckOverCallback(string name)
            {
                if (!_overCallbackList.get(out OverCallbackList callbackList))
                {
                    callbackList.names = new LinkedList<string>();
                    _overCallbackList.value = callbackList;
                }
                callbackList.names.AddLast(name);
            }

            public void ClearCallback()
            {
                if (_overCallbackList.get(out OverCallbackList callbackList))
                {
                    while (0 != callbackList.names.Count)
                    {
                        Methods.Remove(callbackList.names.First.Value);
                        callbackList.names.RemoveFirst();
                    }
                }
            }

            public string OverCallback(Func<object[], Task> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverCallback(Func<object[], ValueTask> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverCallback(Func<object[], ValueTask<void_type>> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverCallback<R>(Func<object[], Task<R>> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverCallback<R>(Func<object[], ValueTask<R>> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverCallback(Action<object[]> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverCallback<R>(Func<object[], R> callback)
            {
                string name = Methods.GenName;
                Methods.Bind(name, callback);
                CheckOverCallback(name);
                return name;
            }

            public string OverObj<T>(T obj)
            {
                string name = Methods.GenName;
                Methods.BindObj(name, obj);
                CheckOverCallback(name);
                return name;
            }

            public async Task<Result> Call(int timed, string name, params object[] args)
            {
                long requestId = 0;
                generator sendAction = null;
                _overSend.remove(out OverSend overSend);
                _overCancel.remove(out OverCancel overCancel);
                try
                {
                    if (_rpcChan.closed)
                    {
                        return new Result { state = ReplyState.Fail };
                    }
                    if (!overCancel.Nil && overCancel.wg.is_done)
                    {
                        return new Result { state = ReplyState.LocalCancel };
                    }
                    if (null != overSend && overSend.actions.Count > 0)
                    {
                        generator.go(out sendAction, generator.self_strand(), async delegate ()
                        {
                            try
                            {
                                generator.lock_stop();
                                await overSend.Wait();
                                if (overSend.Closed)
                                {
                                    overSend.actions.Clear();
                                }
                                generator.unlock_stop();
                                while (overSend.actions.Count > 0)
                                {
                                    generator.lock_stop();
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(false);
                                    generator.unlock_stop();
                                }
                            }
                            catch (generator.stop_exception)
                            {
                                while (overSend.actions.Count > 0)
                                {
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(true);
                                }
                                throw;
                            }
                        });
                    }
                    requestId = Interlocked.Increment(ref _idCount);
                    csp_invoke_wrap<Result> resultWrap = await generator.csp_invoke(_rpcChan, new RpcParam { id = requestId, timed = timed, args = args, overSend = overSend, overCancel = overCancel, request = new Request { name = name, sends = overSend?.Sends() } });
                    if (chan_state.ok != resultWrap.state)
                    {
                        if (chan_state.closed == resultWrap.state)
                        {
                            requestId = 0;
                            overSend?.Close();
                        }
                        return new Result { state = ReplyState.Fail };
                    }
                    switch (resultWrap.result.state)
                    {
                        case ReplyState.Overtime:
                        case ReplyState.LocalCancel:
                            return resultWrap.result;
                        default:
                            if (ReplyState.Success == resultWrap.result.state && 0 == timed && null != sendAction)
                            {
                                await generator.wait_other(sendAction);
                            }
                            requestId = 0;
                            return resultWrap.result;
                    }
                }
                catch (generator.stop_exception)
                {
                    if (null != sendAction)
                    {
                        if (_rpcChan.closed)
                        {
                            requestId = 0;
                            overSend.Close();
                        }
                        else if (!_rpcChan.strand.running_in_this_thread())
                        {
                            _rpcChan.strand.post(delegate ()
                            {
                                if (_rpcChan.closed)
                                {
                                    overSend.Close();
                                }
                            });
                        }
                    }
                    throw;
                }
                finally
                {
                    generator.lock_shield();
                    if (null != sendAction)
                    {
                        await generator.stop_other(sendAction);
                    }
                    if (0 != requestId)
                    {
                        _cancelRpcChan.post(requestId);
                    }
                    ClearCallback();
                    await generator.unlock_shield();
                }
            }

            public Task<Result> Call(string name, params object[] args)
            {
                return Call(-1, name, args);
            }

            public async Task<Result<R>> Call<R>(int ms, string name, params object[] args)
            {
                Result result = await Call(ms, name, args);
                if (result.state != ReplyState.Success)
                {
                    return new Result<R> { state = result.state, message = result.message };
                }
                try
                {
                    return new Result<R> { state = result.state, result = (R)result.result };
                }
                catch (Exception)
                {
                    return new Result<R> { state = ReplyState.ResultTypeError };
                }
            }

            public Task<Result<R>> Call<R>(string name, params object[] args)
            {
                return Call<R>(-1, name, args);
            }

            public Task<Result> Post(string name, params object[] args)
            {
                return Call(0, name, args);
            }

            public void RemoteClose()
            {
                _remoteCmdChan.post(DataType.Close);
            }

            public void NoKeep()
            {
                _remoteCmdChan.post(DataType.NoKeep);
            }

            public ValueTask<csp_invoke_wrap<void_type>> CancelNamedSend(SendName name)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                return generator.csp_invoke(_cancelSendChan, name.id);
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(ArraySegment<byte> data)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, data.Count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendByteChan, new SendByteParam { id = -1L, timed = -1, data = data });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(byte[] data, int offset, int count)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendByteChan, new SendByteParam { id = -1L, timed = -1, data = new ArraySegment<byte>(data, offset, count) });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendPtrChan, new SendPtrParam { id = -1L, timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(SafeHandle file, long offset, int count, object pinnedObj = null)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendFileChan, new SendFileParam { id = -1L, timed = -1, file = file, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<int>> Recv(ArraySegment<byte> buff)
            {
                return generator.csp_invoke(_recvByteChan, new RecvByteParam { timed = -1, buff = buff });
            }

            public ValueTask<csp_invoke_wrap<int>> Recv(byte[] buff, int offset, int count)
            {
                return generator.csp_invoke(_recvByteChan, new RecvByteParam { timed = -1, buff = new ArraySegment<byte>(buff, offset, count) });
            }

            public ValueTask<csp_invoke_wrap<int>> Recv(IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                return generator.csp_invoke(_recvPtrChan, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, ArraySegment<byte> data)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, data.Count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { id = -1L, timed = -1, data = data });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, byte[] data, int offset, int count)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { id = -1L, timed = -1, data = new ArraySegment<byte>(data, offset, count) });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendPtrChan, timed, new SendPtrParam { id = -1L, timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, SafeHandle file, long offset, int count, object pinnedObj = null)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendFileChan, timed, new SendFileParam { id = -1L, timed = -1, file = file, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<int>> TimedRecv(int timed, ArraySegment<byte> buff)
            {
                return generator.csp_timed_invoke(_recvByteChan, timed, new RecvByteParam { timed = -1, buff = buff });
            }

            public ValueTask<csp_invoke_wrap<int>> TimedRecv(int timed, byte[] buff, int offset, int count)
            {
                return generator.csp_timed_invoke(_recvByteChan, timed, new RecvByteParam { timed = -1, buff = new ArraySegment<byte>(buff, offset, count) });
            }

            public ValueTask<csp_invoke_wrap<int>> TimedRecv(int timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                return generator.csp_timed_invoke(_recvPtrChan, timed, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, ArraySegment<byte> data)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, data.Count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { id = -1L, timed = timed.value2, data = data });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, byte[] data, int offset, int count)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { id = -1L, timed = timed.value2, data = new ArraySegment<byte>(data, offset, count) });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendPtrChan, timed.value1, new SendPtrParam { id = -1L, timed = timed.value2, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, SafeHandle file, long offset, int count, object pinnedObj = null)
            {
                OverSendState sendState = CheckOverSendState(new SendName { id = -1L }, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendFileChan, timed.value1, new SendFileParam { id = -1L, timed = timed.value2, file = file, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, ArraySegment<byte> buff)
            {
                return generator.csp_timed_invoke(_recvByteChan, timed.value1, new RecvByteParam { timed = timed.value2, buff = buff });
            }

            public ValueTask<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, byte[] buff, int offset, int count)
            {
                return generator.csp_timed_invoke(_recvByteChan, timed.value1, new RecvByteParam { timed = timed.value2, buff = new ArraySegment<byte>(buff, offset, count) });
            }

            public ValueTask<csp_invoke_wrap<int>> TimedRecv(tuple<int, int> timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                return generator.csp_timed_invoke(_recvPtrChan, timed.value1, new RecvPtrParam { timed = timed.value2, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedSend(SendName name, ArraySegment<byte> data)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, data.Count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendByteChan, new SendByteParam { id = name.id, timed = -1, data = data });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedSend(SendName name, byte[] data, int offset, int count)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendByteChan, new SendByteParam { id = name.id, timed = -1, data = new ArraySegment<byte>(data, offset, count) });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedSend(SendName name, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendPtrChan, new SendPtrParam { id = name.id, timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedSend(SendName name, SafeHandle file, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_invoke(_sendFileChan, new SendFileParam { id = name.id, timed = -1, file = file, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public async Task<csp_invoke_wrap<int>> NamedRecv(SendName name, ArraySegment<byte> buff)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_invoke(recvChan, new RecvByteParam { timed = -1, buff = buff });
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> NamedRecv(SendName name, byte[] buff, int offset, int count)
            {
                return NamedRecv(name, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> NamedRecv(SendName name, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_invoke(recvChan, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                await generator.unlock_shield();
                return recvState;
            }

            public async Task<csp_invoke_wrap<int>> NamedRecv(OverRecv name, ArraySegment<byte> buff)
            {
                Debug.Assert(name.recvName.name.id > 0, "数据命名ID要大于0");
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.recvName.name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_invoke(recvChan, new RecvByteParam { timed = -1, buff = buff });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> NamedRecv(OverRecv name, byte[] buff, int offset, int count)
            {
                return NamedRecv(name, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> NamedRecv(OverRecv name, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.recvName.name.id > 0, "数据命名ID要大于0");
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.recvName.name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_invoke(recvChan, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                await generator.unlock_shield();
                return recvState;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, int timed, ArraySegment<byte> data)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, data.Count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { id = name.id, timed = -1, data = data });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, int timed, byte[] data, int offset, int count)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { id = name.id, timed = -1, data = new ArraySegment<byte>(data, offset, count) });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, int timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendPtrChan, timed, new SendPtrParam { id = name.id, timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, int timed, SafeHandle file, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendFileChan, timed, new SendFileParam { id = name.id, timed = -1, file = file, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(SendName name, int timed, ArraySegment<byte> buff)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed, new RecvByteParam { timed = -1, buff = buff });
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> NamedTimedRecv(SendName name, int timed, byte[] buff, int offset, int count)
            {
                return NamedTimedRecv(name, timed, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(SendName name, int timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                await generator.unlock_shield();
                return recvState;
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(OverRecv name, int timed, ArraySegment<byte> buff)
            {
                Debug.Assert(name.recvName.name.id > 0, "数据命名ID要大于0");
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.recvName.name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed, new RecvByteParam { timed = -1, buff = buff });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> NamedTimedRecv(OverRecv name, int timed, byte[] buff, int offset, int count)
            {
                return NamedTimedRecv(name, timed, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(OverRecv name, int timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.recvName.name.id > 0, "数据命名ID要大于0");
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.recvName.name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                await generator.unlock_shield();
                return recvState;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, tuple<int, int> timed, ArraySegment<byte> data)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, data.Count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { id = name.id, timed = timed.value2, data = data });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, tuple<int, int> timed, byte[] data, int offset, int count)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { id = name.id, timed = timed.value2, data = new ArraySegment<byte>(data, offset, count) });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, tuple<int, int> timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendPtrChan, timed.value1, new SendPtrParam { id = name.id, timed = timed.value2, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public ValueTask<csp_invoke_wrap<void_type>> NamedTimedSend(SendName name, tuple<int, int> timed, SafeHandle file, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                OverSendState sendState = CheckOverSendState(name, count);
                ValueTask<csp_invoke_wrap<void_type>> task = generator.csp_timed_invoke(_sendFileChan, timed.value1, new SendFileParam { id = name.id, timed = timed.value2, file = file, offset = offset, count = count, pinnedObj = pinnedObj });
                sendState?.SetTask(task);
                return task;
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(SendName name, tuple<int, int> timed, ArraySegment<byte> buff)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed.value1, new RecvByteParam { timed = timed.value2, buff = buff });
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> NamedTimedRecv(SendName name, tuple<int, int> timed, byte[] buff, int offset, int count)
            {
                return NamedTimedRecv(name, timed, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(SendName name, tuple<int, int> timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.id > 0, "数据命名ID要大于0");
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed.value1, new RecvPtrParam { timed = timed.value2, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                await generator.unlock_shield();
                return recvState;
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(OverRecv name, tuple<int, int> timed, ArraySegment<byte> buff)
            {
                Debug.Assert(name.recvName.name.id > 0, "数据命名ID要大于0");
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.recvName.name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed.value1, new RecvByteParam { timed = timed.value2, buff = buff });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> NamedTimedRecv(OverRecv name, tuple<int, int> timed, byte[] buff, int offset, int count)
            {
                return NamedTimedRecv(name, timed, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> NamedTimedRecv(OverRecv name, tuple<int, int> timed, IntPtr pointer, long offset, int count, object pinnedObj = null)
            {
                Debug.Assert(name.recvName.name.id > 0, "数据命名ID要大于0");
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { id = name.recvName.name.id, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed.value1, new RecvPtrParam { timed = timed.value2, pointer = pointer, offset = offset, count = count, pinnedObj = pinnedObj });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                await generator.unlock_shield();
                return recvState;
            }

            struct ReplyMapValue
            {
                public async_timer timer;
                public csp_result<Result> result;
            }

            struct SendRequestParam
            {
                public long id;
                public object[] args;
                public Request request;
                public OverSend overSend;
            }

            struct RecvRequestParam
            {
                public long id;
                public bool cancel;
                public object[] args;
                public Request request;
            }

            struct RecvReplyParam
            {
                public long id;
                public ReplyState state;
                public object result;
                public Reply reply;
            }

            struct SendReplyParam
            {
                public long id;
                public object result;
                public Reply reply;
            }

            struct SendBuffParam
            {
                public int count;
                public OverSend overSend;
            }

            private async Task Run()
            {
                generator.children ioChild = new generator.children();
                chan_lost_msg<csp_wait_wrap<Result, RpcParam>> rpcLost = new chan_lost_msg<csp_wait_wrap<Result, RpcParam>>();
                Dictionary<long, ReplyMapValue> replyMap = new Dictionary<long, ReplyMapValue>();
                chan<SendRequestParam> sendRequestChan = chan<SendRequestParam>.make(-1);
                Action<ExitCode> setCode = (ExitCode code) => Interlocked.CompareExchange(ref _exitCode, (int)code, (int)ExitCode.Undefined);
                try
                {
                    bool noKeep = false;
                    chan<RecvRequestParam> recvRequestChan = chan<RecvRequestParam>.make(-1);
                    chan<RecvReplyParam> recvReplyChan = chan<RecvReplyParam>.make(-1);
                    chan<SendReplyParam> sendReplyChan = chan<SendReplyParam>.make(-1);
                    ioChild.go(async delegate ()
                    {
                        byte[] recvHead = new byte[17];
                        byte[] recvBuff1 = new byte[1024 * 1024];
                        byte[] recvBuff2 = new byte[1024 * 1024];
                        DataType lastType = DataType.Keep;
                        async_timer timer = new async_timer();
                        Action timerKeepHandler = delegate ()
                        {
                            switch (lastType)
                            {
                                case DataType.Bin:
                                    setCode(ExitCode.RecvOvertime);
                                    break;
                                default:
                                    if (!noKeep)
                                    {
                                        setCode(ExitCode.KeepOvertime);
                                        break;
                                    }
                                    return;
                            }
                            _action.stop();
                        };
                        Action timerReadHandler = delegate ()
                        {
                            setCode(ExitCode.ReadOvertime);
                            _action.stop();
                        };
                        timer.timeout(_keep, timerKeepHandler);
                        BinaryFormatter deserializer = new BinaryFormatter();
                        Map<long, NamedCsp> namedMap = new Map<long, NamedCsp>(true);
                        chan_lost_msg<NamedRecvParam> namedLost = new chan_lost_msg<NamedRecvParam>();
                        try
                        {
                            Task deserializeTask = generator.non_async();
                            while (true)
                            {
                                if (!await _socket.read(recvHead))
                                {
                                    goto socketClosed;
                                }
                                timer.restart();
                                ReadHead(recvHead, out long id, out int len1, out int len2, out DataType type);
                                lastType = type;
                                switch (type)
                                {
                                    case DataType.Keep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        break;
                                    case DataType.NoKeep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        noKeep = true;
                                        break;
                                    case DataType.RequestCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        recvRequestChan.post(new RecvRequestParam { id = id, cancel = true });
                                        break;
                                    case DataType.Request:
                                    case DataType.Reply:
                                        if (len1 <= 0 || len2 < 0 || len1 + len2 > recvBuff1.Length)
                                        {
                                            goto dataHeadError;
                                        }
                                        if (!await _socket.read(new ArraySegment<byte>(recvBuff1, 0, len1 + len2)))
                                        {
                                            goto socketClosed;
                                        }
                                        await generator.wait_task(deserializeTask);
                                        Swap(ref recvBuff1, ref recvBuff2);
                                        (deserializeTask = new Task(delegate ()
                                        {
                                            MemoryStream stream = new MemoryStream(recvBuff2, 0, len1 + len2);
                                            switch (type)
                                            {
                                                case DataType.Request:
                                                    try
                                                    {
                                                        Request request = (Request)deserializer.Deserialize(stream);
                                                        try
                                                        {
                                                            object[] args = 0 != len2 ? (object[])deserializer.Deserialize(stream) : null;
                                                            recvRequestChan.post(new RecvRequestParam { id = id, cancel = false, args = args, request = request });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            sendReplyChan.post(new SendReplyParam { id = id, reply = new Reply { state = ReplyState.RemoteDeserializeError } });
                                                            if (null != request.sends)
                                                            {
                                                                recvRequestChan.post(new RecvRequestParam { id = id, cancel = true, request = request });
                                                            }
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        setCode(ExitCode.RequestDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                                case DataType.Reply:
                                                    try
                                                    {
                                                        Reply reply = (Reply)deserializer.Deserialize(stream);
                                                        try
                                                        {
                                                            object result = 0 != len2 ? deserializer.Deserialize(stream) : null;
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, result = result, reply = reply });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalDeserializeError } });
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        setCode(ExitCode.ReplyDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                            }
                                        })).Start();
                                        break;
                                    case DataType.Bin:
                                        if (0 != len1 || len2 <= 0)
                                        {
                                            goto dataHeadError;
                                        }
                                        int position = 0;
                                        Func<RecvByteParam, Task<int>> recvByteAction = async delegate (RecvByteParam param)
                                        {
                                            int count = param.buff.Count;
                                            if (count > len2 - position)
                                            {
                                                count = len2 - position;
                                            }
                                            if (count <= 0)
                                            {
                                                timer.restart();
                                                return 0;
                                            }
                                            try
                                            {
                                                timer.cancel();
                                                if (param.timed >= 0)
                                                {
                                                    timer.timeout(param.timed, timerReadHandler);
                                                }
                                                socket_result result = default;
                                                using (generator.using_lock) result = await _socket.read(new ArraySegment<byte>(param.buff.Array, param.buff.Offset, count));
                                                if (!result)
                                                {
                                                    position = -1;
                                                    return -1;
                                                }
                                                position += result.size;
                                                return result.size;
                                            }
                                            finally
                                            {
                                                if (param.timed >= 0)
                                                {
                                                    timer.cancel();
                                                }
                                                timer.timeout(_keep, timerKeepHandler);
                                            }
                                        };
                                        Func<RecvPtrParam, Task<int>> recvPtrAction = async delegate (RecvPtrParam param)
                                        {
                                            int count = param.count;
                                            if (count > len2 - position)
                                            {
                                                count = len2 - position;
                                            }
                                            if (count <= 0)
                                            {
                                                timer.restart();
                                                return 0;
                                            }
                                            try
                                            {
                                                timer.cancel();
                                                if (param.timed >= 0)
                                                {
                                                    timer.timeout(param.timed, timerReadHandler);
                                                }
                                                socket_result result = default;
                                                if (_socket is socket_tcp)
                                                {
                                                    using (generator.using_lock) result = await ((socket_tcp)_socket).read(param.pointer, param.offset, count, param.pinnedObj);
                                                }
                                                else if (_socket is socket_pipe)
                                                {
                                                    using (generator.using_lock) result = await ((socket_pipe)_socket).read(param.pointer, param.offset, count, param.pinnedObj);
                                                }
                                                if (!result)
                                                {
                                                    position = -1;
                                                    return -1;
                                                }
                                                position += result.size;
                                                return result.size;
                                            }
                                            finally
                                            {
                                                if (param.timed >= 0)
                                                {
                                                    timer.cancel();
                                                }
                                                timer.timeout(_keep, timerKeepHandler);
                                            }
                                        };
                                        if (id > 0)
                                        {
                                            while (-1 != position && position != len2)
                                            {
                                                var first = namedMap.FindFirst(id);
                                                if (null == first)
                                                {
                                                    break;
                                                }
                                                switch (first.Value.Type)
                                                {
                                                    case NamedType.Byte:
                                                        await generator.csp_wait((NamedByteCsp)first.Value, recvByteAction);
                                                        break;
                                                    case NamedType.Ptr:
                                                        await generator.csp_wait((NamedPtrCsp)first.Value, recvPtrAction);
                                                        break;
                                                }
                                                namedMap.Remove(first);
                                            }
                                            while (-1 != position && position != len2)
                                            {
                                                chan_recv_wrap<NamedRecvParam> namedCsp = await _namedRecvChan.receive(namedLost);
                                                var tempNode = namedMap.Insert(namedCsp.msg.id, namedCsp.msg.csp);
                                                if (namedCsp.msg.id != id)
                                                {
                                                    continue;
                                                }
                                                switch (namedCsp.msg.csp.Type)
                                                {
                                                    case NamedType.Byte:
                                                        await generator.csp_wait((NamedByteCsp)namedCsp.msg.csp, recvByteAction);
                                                        break;
                                                    case NamedType.Ptr:
                                                        await generator.csp_wait((NamedPtrCsp)namedCsp.msg.csp, recvPtrAction);
                                                        break;
                                                }
                                                namedMap.Remove(tempNode);
                                            }
                                        }
                                        else
                                        {
                                            await generator.select()
                                            .case_receive(_recvByteChan, recvByteAction)
                                            .case_receive(_recvPtrChan, recvPtrAction)
                                            .loop(delegate ()
                                            {
                                                if (-1 == position || position == len2)
                                                {
                                                    generator.select_chans.stop_all();
                                                }
                                                return generator.non_async();
                                            });
                                        }
                                        if (-1 == position)
                                        {
                                            goto socketClosed;
                                        }
                                        break;
                                    case DataType.BinCancel:
                                        if (0 != len1 || 0 != len2 || id <= 0)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            var first = namedMap.FindFirst(id);
                                            if (null != first)
                                            {
                                                switch (first.Value.Type)
                                                {
                                                    case NamedType.Byte:
                                                        await generator.csp_wait((NamedByteCsp)first.Value, (RecvByteParam _) => new ValueTask<int>(-2));
                                                        break;
                                                    case NamedType.Ptr:
                                                        await generator.csp_wait((NamedPtrCsp)first.Value, (RecvPtrParam _) => new ValueTask<int>(-2));
                                                        break;
                                                }
                                                namedMap.Remove(first);
                                            }
                                            else
                                            {
                                                chan_recv_wrap<NamedRecvParam> namedCsp = await _namedRecvChan.receive(namedLost);
                                                var tempNode = namedMap.Insert(namedCsp.msg.id, namedCsp.msg.csp);
                                                if (namedCsp.msg.id == id)
                                                {
                                                    switch (namedCsp.msg.csp.Type)
                                                    {
                                                        case NamedType.Byte:
                                                            await generator.csp_wait((NamedByteCsp)namedCsp.msg.csp, (RecvByteParam _) => new ValueTask<int>(-2));
                                                            break;
                                                        case NamedType.Ptr:
                                                            await generator.csp_wait((NamedPtrCsp)namedCsp.msg.csp, (RecvPtrParam _) => new ValueTask<int>(-2));
                                                            break;
                                                    }
                                                    namedMap.Remove(tempNode);
                                                }
                                            }
                                        }
                                        break;
                                    case DataType.Close:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        setCode(ExitCode.RemoteClose);
                                        return;
                                    default:
                                        goto dataHeadError;
                                }
                            }
dataHeadError:
                            setCode(ExitCode.DataHeadError);
                            return;
socketClosed:
                            setCode(ExitCode.SocketClosed);
                            return;
                        }
                        finally
                        {
                            generator.lock_stop();
                            timer.cancel();
                            _action.stop();
                            _namedRecvChan.close();
                            _recvByteChan.close();
                            _recvPtrChan.close();
                            if (namedLost.has)
                            {
                                namedLost.msg.csp.Close();
                                namedLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await _namedRecvChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg.csp.Close();
                            }
                            foreach (var item in namedMap)
                            {
                                item.value2.Close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        byte[] sendHead = new byte[17];
                        byte[] sendBuff1 = new byte[sendHead.Length + 1024 * 1024];
                        byte[] sendBuff2 = new byte[sendHead.Length + 1024 * 1024];
                        wait_group sendBuffWg = new wait_group();
                        chan<void_type> keepChan = chan<void_type>.make(1);
                        Action timerKeepHandler = keepChan.wrap_try_default();
                        Action timerWriteHandler = delegate ()
                        {
                            setCode(ExitCode.WriteOvertime);
                            _action.stop();
                        };
                        async_timer timer = new async_timer();
                        timer.interval(_keep / 2, timerKeepHandler);
                        chan_lost_msg<SendBuffParam> sendBuffLost = new chan_lost_msg<SendBuffParam>();
                        chan_lost_msg<SendRequestParam> sendRequestLost = new chan_lost_msg<SendRequestParam>();
                        chan<SendBuffParam> sendBuffChan = chan<SendBuffParam>.make(1);
                        generator.children serializerChild = new generator.children();
                        serializerChild.go(async delegate ()
                        {
                            BinaryFormatter serializer = new BinaryFormatter();
                            try
                            {
                                await generator.select().case_receive(sendReplyChan, async delegate (SendReplyParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            MemoryStream sendStream = new MemoryStream(sendBuff1, sendHead.Length, sendBuff1.Length - sendHead.Length);
                                            serializer.Serialize(sendStream, param.reply);
                                            len1 = (int)sendStream.Position;
                                            if (null != param.result)
                                            {
                                                try
                                                {
                                                    serializer.Serialize(sendStream, param.result);
                                                    len2 = (int)sendStream.Position - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    sendStream.Position = 0;
                                                    serializer.Serialize(sendStream, new Reply { state = ReplyState.RemoteSerializeError });
                                                    len1 = (int)sendStream.Position;
                                                }
                                            }
                                        }
                                        catch (Exception)
                                        {
                                            setCode(ExitCode.ReplySerializeError);
                                            throw;
                                        }
                                    });
                                    WriteHead(sendBuff1, param.id, len1, len2, DataType.Reply);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref  sendBuff1, ref sendBuff2);
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2 });
                                }).case_receive(sendRequestChan, async delegate (SendRequestParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    sendRequestLost.set(param);
                                    if (!await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            MemoryStream sendStream = new MemoryStream(sendBuff1, sendHead.Length, sendBuff1.Length - sendHead.Length);
                                            serializer.Serialize(sendStream, param.request);
                                            len1 = (int)sendStream.Position;
                                            if (null != param.args)
                                            {
                                                try
                                                {
                                                    serializer.Serialize(sendStream, param.args);
                                                    len2 = (int)sendStream.Position - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    recvReplyChan.post(new RecvReplyParam { id = param.id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalSerializeError } });
                                                    return false;
                                                }
                                            }
                                            return true;
                                        }
                                        catch (Exception)
                                        {
                                            setCode(ExitCode.RequestSerializeError);
                                            throw;
                                        }
                                    }))
                                    {
                                        param.overSend?.Close();
                                        sendRequestLost.clear();
                                        return;
                                    }
                                    WriteHead(sendBuff1, param.id, len1, len2, DataType.Request);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref sendBuff1, ref sendBuff2);
                                    sendRequestLost.clear();
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2, overSend = param.overSend });
                                }, lostMsg: sendRequestLost).loop();
                            }
                            catch (generator.stop_exception) { throw; }
                            catch (Exception) { }
                            finally
                            {
                                generator.lock_stop();
                                _action.stop();
                                if (sendRequestLost.has)
                                {
                                    sendRequestLost.msg.overSend?.Close();
                                    sendRequestLost.clear();
                                }
                                generator.unlock_stop();
                            }
                        });
                        try
                        {
                            await generator.select().case_receive(_remoteCmdChan, async delegate (DataType cmd)
                            {
                                WriteHead(sendHead, 0L, 0, 0, cmd);
                                switch (cmd)
                                {
                                    case DataType.NoKeep:
                                        noKeep = true;
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                        }
                                        break;
                                    case DataType.Close:
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                        }
                                        setCode(ExitCode.LocalClose);
                                        _remoteCmdChan.close();
                                        await generator.hold();
                                        break;
                                }
                            }).case_receive(_cancelRpcChan, async delegate (long id)
                            {
                                WriteHead(sendHead, id, 0, 0, DataType.RequestCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                            }).case_receive(sendBuffChan, async delegate (SendBuffParam param)
                            {
                                param.overSend?.Notify();
                                if (!await _socket.write(new ArraySegment<byte>(sendBuff2, 0, param.count)))
                                {
                                    generator.select_chans.stop_all();
                                }
                                sendBuffWg.done();
                            }, lostMsg: sendBuffLost).case_receive(_cancelSendChan, async delegate (long id)
                            {
                                WriteHead(sendHead, id, 0, 0, DataType.BinCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                            }).case_receive(_sendByteChan, async delegate (SendByteParam param)
                            {
                                if (param.data.Count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.id, 0, param.data.Count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                                try
                                {
                                    timer.cancel();
                                    if (param.timed >= 0)
                                    {
                                        timer.timeout(param.timed, timerWriteHandler);
                                    }
                                    socket_result result = default;
                                    using (generator.using_lock) result = await _socket.write(param.data);
                                    if (!result)
                                    {
                                        generator.select_chans.stop_all();
                                    }
                                }
                                finally
                                {
                                    if (param.timed >= 0)
                                    {
                                        timer.cancel();
                                    }
                                    timer.interval(_keep / 2, timerKeepHandler);
                                }
                            }).case_receive(_sendPtrChan, async delegate (SendPtrParam param)
                            {
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.id, 0, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                                try
                                {
                                    timer.cancel();
                                    if (param.timed >= 0)
                                    {
                                        timer.timeout(param.timed, timerWriteHandler);
                                    }
                                    socket_result result = default;
                                    if (_socket is socket_tcp)
                                    {
                                        using (generator.using_lock) result = await ((socket_tcp)_socket).write(param.pointer, param.offset, param.count, param.pinnedObj);
                                    }
                                    else if (_socket is socket_pipe)
                                    {
                                        using (generator.using_lock) result = await ((socket_pipe)_socket).write(param.pointer, param.offset, param.count, param.pinnedObj);
                                    }
                                    if (!result)
                                    {
                                        generator.select_chans.stop_all();
                                    }
                                }
                                finally
                                {
                                    if (param.timed >= 0)
                                    {
                                        timer.cancel();
                                    }
                                    timer.interval(_keep / 2, timerKeepHandler);
                                }
                            }).case_receive(_sendFileChan, async delegate (SendFileParam param)
                            {
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.id, 0, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                                try
                                {
                                    timer.cancel();
                                    if (param.timed >= 0)
                                    {
                                        timer.timeout(param.timed, timerWriteHandler);
                                    }
                                    socket_result result = default;
                                    if (_socket is socket_tcp)
                                    {
                                        using (generator.using_lock) result = await ((socket_tcp)_socket).send_file(param.file, param.offset, param.count, param.pinnedObj);
                                    }
                                    if (!result)
                                    {
                                        generator.select_chans.stop_all();
                                    }
                                }
                                finally
                                {
                                    if (param.timed >= 0)
                                    {
                                        timer.cancel();
                                    }
                                    timer.interval(_keep / 2, timerKeepHandler);
                                }
                            }).case_receive(keepChan, async delegate ()
                            {
                                WriteHead(sendHead, 0L, 0, 0, DataType.Keep);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                            }).loop();
                            setCode(ExitCode.SocketClosed);
                        }
                        finally
                        {
                            generator.lock_stop();
                            await serializerChild.stop();
                            timer.cancel();
                            _action.stop();
                            _sendPtrChan.close();
                            _sendByteChan.close();
                            _sendFileChan.close();
                            _cancelRpcChan.close();
                            _cancelSendChan.close();
                            _remoteCmdChan.close();
                            sendBuffChan.close();
                            if (sendBuffLost.has)
                            {
                                sendBuffLost.msg.overSend?.Close();
                                sendBuffLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await sendBuffChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg.overSend?.Close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        mt19937 mt = new mt19937();
                        shared_strand selfStrand = generator.self_strand();
                        generator.children callChild = new generator.children();
                        Dictionary<long, RpcCancel> rpcCancelDict = new Dictionary<long, RpcCancel>();
                        while (true)
                        {
                            RecvRequestParam request = await recvRequestChan.receive();
                            OverRecv[] recvs = null;
                            if (null != request.request.sends)
                            {
                                recvs = new OverRecv[request.request.sends.Length];
                                for (int i = 0; i < request.request.sends.Length; i++)
                                {
                                    recvs[i] = new OverRecv { recvName = request.request.sends[i] };
                                }
                            }
                            if (request.cancel)
                            {
                                if (rpcCancelDict.TryGetValue(request.id, out RpcCancel rpcCancel))
                                {
                                    rpcCancelDict.Remove(request.id);
                                    rpcCancel.wg.done();
                                }
                                if (null != recvs)
                                {
                                    callChild.free_go(selfStrand, () => DiscardRecv(recvs));
                                }
                                continue;
                            }
                            Func<async_result_wrap<object, ReplyState>, object[], Task> handler;
                            if (null == request.request.name || null == request.args || !_methods.Get(request.request.name, out handler))
                            {
                                sendReplyChan.post(new SendReplyParam { id = request.id, reply = new Reply { state = ReplyState.NotFound } });
                                if (null != recvs)
                                {
                                    callChild.free_go(selfStrand, () => DiscardRecv(recvs));
                                }
                            }
                            else
                            {
                                RpcCancel rpcCancel = new RpcCancel { wg = new wait_group(1) };
                                rpcCancelDict.Add(request.id, rpcCancel);
                                callChild.free_go(_strands[(int)(_strands.Length * mt.NextDouble())], async delegate ()
                                {
                                    bool cancel = false;
                                    object result = default;
                                    Reply reply = new Reply { };
                                    try
                                    {
                                        try
                                        {
                                            _session.value = this;
                                            _rpcCancel.value = rpcCancel;
                                            _recvList.value = new RecvList { recvs = recvs };
                                            async_result_wrap<object, ReplyState> resultWrap = new async_result_wrap<object, ReplyState> { value2 = ReplyState.Success };
                                            await handler(resultWrap, request.args);
                                            reply.state = resultWrap.value2;
                                            result = resultWrap.value1;
                                        }
                                        catch (generator.stop_exception)
                                        {
                                            reply.state = ReplyState.Stopped;
                                            throw;
                                        }
                                        catch (CancelException)
                                        {
                                            reply.state = ReplyState.RemoteCancel;
                                            cancel = true;
                                        }
                                        catch (ArgumentException)
                                        {
                                            reply.state = ReplyState.ArgumentException;
                                        }
                                        catch (TargetParameterCountException)
                                        {
                                            reply.state = ReplyState.TargetParameterCountException;
                                        }
                                        catch (Exception ec)
                                        {
                                            reply.state = ReplyState.Exception;
                                            if (null != ec.InnerException)
                                            {
                                                Exception inner = ec.InnerException;
                                                reply.message = $"{inner.Message}\r\n{ec.Message}\r\n{inner.Source}\r\n{ec.Source}\r\n{inner.StackTrace}\r\n{ec.StackTrace}";
                                            }
                                            else
                                            {
                                                reply.message = $"{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}";
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        generator.lock_stop();
                                        if (!cancel && request.request.reply)
                                        {
                                            sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                        }
                                        if (selfStrand.running_in_this_thread())
                                        {
                                            if (rpcCancelDict.Remove(request.id) && cancel && request.request.reply)
                                            {
                                                sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                            }
                                        }
                                        else
                                        {
                                            selfStrand.post(delegate ()
                                            {
                                                if (rpcCancelDict.Remove(request.id) && cancel && request.request.reply)
                                                {
                                                    sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                                }
                                            });
                                        }
                                        await generator.children.stop(generator.all_children());
                                        if (null != recvs)
                                        {
                                            await DiscardRecv(recvs);
                                        }
                                        generator.unlock_stop();
                                    }
                                });
                            }
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        while (true)
                        {
                            RecvReplyParam reply = await recvReplyChan.receive();
                            if (replyMap.TryGetValue(reply.id, out var replyPack))
                            {
                                replyMap.Remove(reply.id);
                                replyPack.timer?.cancel();
                                if (reply.state == ReplyState.Success)
                                {
                                    replyPack.result.complete(new Result { state = reply.reply.state, result = reply.result, message = reply.reply.message });
                                }
                                else
                                {
                                    replyPack.result.complete(new Result { state = reply.state });
                                }
                            }
                        }
                    });
                    while (true)
                    {
                        var rpc = await _rpcChan.wait(rpcLost);
                        if (rpc.state != chan_state.ok)
                        {
                            break;
                        }
                        long id = rpc.msg.id;
                        if (rpc.msg.timed > 0)
                        {
                            rpc.msg.request.reply = true;
                            async_timer timer = new async_timer();
                            replyMap.Add(id, new ReplyMapValue { timer = timer, result = rpc.result });
                            timer.timeout(rpc.msg.timed, () => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Overtime }));
                        }
                        else if (rpc.msg.timed < 0)
                        {
                            rpc.msg.request.reply = true;
                            replyMap.Add(id, new ReplyMapValue { result = rpc.result });
                        }
                        else
                        {
                            rpc.msg.request.reply = false;
                            rpc.complete(new Result { state = ReplyState.Success });
                        }
                        if (null != rpc.msg.overCancel.wg)
                        {
                            rpc.msg.overCancel.wg.async_wait(() => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.LocalCancel }));
                        }
                        sendRequestChan.post(new SendRequestParam { id = id, args = rpc.msg.args, request = rpc.msg.request, overSend = rpc.msg.overSend });
                    }
                    setCode(ExitCode.SessionClose);
                }
                catch (generator.stop_exception)
                {
                    setCode(ExitCode.SessionClose);
                    throw;
                }
                finally
                {
                    generator.lock_stop();
                    _socket.close();
                    await ioChild.stop();
                    _rpcChan.close();
                    sendRequestChan.close();
                    if (rpcLost.has)
                    {
                        rpcLost.msg.msg.overSend?.Close();
                        rpcLost.msg.fail();
                        rpcLost.clear();
                    }
                    foreach (var item in replyMap)
                    {
                        item.Value.timer?.cancel();
                        item.Value.result.fail();
                    }
                    while (true)
                    {
                        var wrap = await _rpcChan.wait();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                        wrap.fail();
                    }
                    while (true)
                    {
                        var wrap = await sendRequestChan.receive();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                    }
                    generator.unlock_stop();
                }
            }
        }
    }
}
